package walletdao

import (
	"strings"
	"time"
	"wzgames/internal/gdao"
	"wzgames/internal/model/mcomm"
	"wzgames/internal/model/user"
	"wzgames/internal/response"
)

type WalletDao gdao.DaoSource

const sqlGetTxIdByBTxNo = "select * from wallet_transfer_tx where `fromid`=? limit 1"

func (dao *WalletDao) GetTidByBTxNo(bTxNo string) (*user.WalletTxHash, error) {
	tx := &user.WalletTxHash{}
	err := dao.Get(tx, sqlGetTxIdByBTxNo, bTxNo)
	return tx, err
}

const sqlGetWalletByUid = "select `uid`,`currid`,`agtid`,`balance`,`wv`,`created`,`updated` from wallet where `uid`=? and `currid`=? limit 1"

func (dao *WalletDao) GetWalletByUid(uid uint64, currId int32) (*user.WalletEntity, error) {
	w := &user.WalletEntity{}
	err := dao.Get(w, sqlGetWalletByUid, uid, currId)
	if w != nil {
		w.Balance = response.TrimAmtZeros(w.Balance)
	}
	return w, err
}

const sqlGetTransferByTxId = "select * from wallet_transfer where `tid`=? limit 1"

func (dao *WalletDao) GetTransferByTxId(tid uint64) (*user.WalletTransfer, error) {
	w := &user.WalletTransfer{}
	err := dao.Get(w, sqlGetTransferByTxId, tid)
	return w, err
}

const sqlCreateBTxHash = "insert into wallet_transfer_tx(`fromid`,`tid`) values(:fromid,:tid)"

func (dao *WalletDao) CreateBTxHash(tx *user.WalletTxHash) error {
	_, err := dao.NamedExec(sqlCreateBTxHash, tx)
	return err
}

const sqlCreateTransfer = "insert into wallet_transfer(`tid`,`uid`,`agtid`,`agtuid`,`uname`,`currid`,`ucurrency`,`actype`,`status`,`amount`,`balance`,`obalance`,`fromid`,`created`,`updated`)" +
	" values(:tid,:uid,:agtid,:agtuid,:uname,:currid,:ucurrency,:actype,:status,:amount,:balance,:obalance,:fromid,:created,:updated)"

func (dao *WalletDao) CreateWalletTransfer(tx *user.WalletTransfer) error {
	_, err := dao.NamedExec(sqlCreateTransfer, tx)
	return err
}

const sqlCreateWallet = "insert into wallet(`uid`,`currid`,`agtid`,`balance`,`wv`,`curr`,`created`,`updated`) values(:uid,:currid,:agtid,:balance,:wv,:curr,:created,:updated)"

func (dao *WalletDao) CreateWallet(wallet *user.WalletEntity) error {
	_, err := dao.NamedExec(sqlCreateWallet, wallet)
	return err
}

const sqlIncBalance = "update wallet set `balance`=`balance`+cast(? as decimal(30,18)),`wv`=`wv`+1,`updated`=? where `uid`=? and `currid`=?"

func (dao *WalletDao) IncWalletBalance(uid uint64, currId int32, t time.Time, amt string) (int64, error) {
	result, err := dao.Exec(sqlIncBalance, amt, t, uid, currId)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlIncBalanceWithWv = "update wallet set `balance`=`balance`+cast(? as decimal(30,18)),`wv`=`wv`+1,`updated`=? where `uid`=? and `currid`=? and `wv`=?"

func (dao *WalletDao) IncWalletBalanceWithWv(wallet *user.WalletEntity, amt string) (int64, error) {
	result, err := dao.Exec(sqlIncBalanceWithWv, amt, wallet.Updated, wallet.Uid, wallet.CurrID, wallet.Wv)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlDecBalance = "update wallet set `balance`=`balance`-cast(? as decimal(30,18)),`wv`=`wv`+1,`updated`=? where `uid`=? and `currid`=? and `wv`=? and `balance`>=?"

func (dao *WalletDao) DecWalletBalance(wallet *user.WalletEntity, amt string) (int64, error) {
	result, err := dao.Exec(sqlDecBalance, amt, wallet.Updated, wallet.Uid, wallet.CurrID, wallet.Wv, amt)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlCreateBetCharge = "insert into wallet_bet_charge(`betid`,`inst`,`uid`,`currid`,`gameid`,`betamt`,`effamt`,`fee`,`bettime`,`balance`,`wv`,`created`,`updated`) " +
	"values(:betid,:inst,:uid,:currid,:gameid,:betamt,:effamt,:fee,:bettime,:balance,:wv,:created,:updated)"

func (dao *WalletDao) CreateBetCharge(tx *user.WalletBetCharge) error {
	_, err := dao.NamedExec(sqlCreateBetCharge, tx)
	return err
}

const sqlGetBetCharge = "select * from wallet_bet_charge where `betid`=? limit 1"

func (dao *WalletDao) GetBetCharge(betId uint64) (*user.WalletBetCharge, error) {
	w := &user.WalletBetCharge{}
	err := dao.Get(w, sqlGetBetCharge, betId)
	return w, err
}

const sqlBetChargeExists = "select count(*) from wallet_bet_charge where `betid`=? limit 1"

func (dao *WalletDao) CheckBetChargeExists(betId uint64) (int, error) {
	var c int
	err := dao.Get(&c, sqlBetChargeExists, betId)
	return c, err
}

const sqlCreateBetPayout = "insert into wallet_bet_payout(`betid`,`win`,`amt`,`gact`,`paytime`,`created`,`updated`) values(:betid,:win,:amt,:gact,:paytime,:created,:updated)"

func (dao *WalletDao) CreateBetPayout(tx *user.WalletBetPayout) error {
	_, err := dao.NamedExec(sqlCreateBetPayout, tx)
	return err
}

const sqlCreateBetCancel = "insert into wallet_bet_cancel(`betid`,`amt`,`dateline`,`created`,`updated`) values(:betid,:amt,:dateline,:created,:updated)"

func (dao *WalletDao) CreateBetCancel(tx *user.WalletBetCancel) error {
	_, err := dao.NamedExec(sqlCreateBetCancel, tx)
	return err
}

const sqlCreateBetPending = "insert into wallet_bet_pending(`betid`,`nodeid`,`gact`,`stm`,`bettime`,`uid`,`currid`,`gameid`,`roundid`,`betamt`,`effamt`,`fee`,`inst`) values(:betid,:nodeid,:gact,:stm,:bettime,:uid,:currid,:gameid,:roundid,:betamt,:effamt,:fee,:inst)"

func (dao *WalletDao) CreateBetPending(data *user.WalletBetPending) error {
	_, err := dao.NamedExec(sqlCreateBetPending, data)
	return err
}

const sqlGetBetPending = "select * from wallet_bet_pending where `betid`=? limit 1"

func (dao *WalletDao) GetBetPending(betId uint64) (*user.WalletBetPending, error) {
	w := &user.WalletBetPending{}
	err := dao.Get(w, sqlGetBetPending, betId)
	return w, err
}

const sqlUpdateBetPendingGAct = "update wallet_bet_pending set `gact`=? where `betid`=?"

func (dao *WalletDao) UpdateBetPendingGAct(betId uint64, gAct mcomm.GameAction) (int64, error) {
	result, err := dao.Exec(sqlUpdateBetPendingGAct, gAct, betId)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlUpdateBetPendingGActWithStm = "update wallet_bet_pending set `gact`=?,`stm`=1 where `betid`=?"

func (dao *WalletDao) UpdateBetPendingGActWithStm(betId uint64, gAct mcomm.GameAction) (int64, error) {
	result, err := dao.Exec(sqlUpdateBetPendingGActWithStm, gAct, betId)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlUpdateBetPendingStm = "update wallet_bet_pending set `stm`=1 where `betid` in("

func (dao *WalletDao) UpdateBetPendingStm(ids string) (int64, error) {
	var sqlTmp = sqlUpdateBetPendingStm + ids + ")"
	result, err := dao.Exec(sqlTmp)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlUpdateBetPendingGActAndStm = "update wallet_bet_pending set `gact`=?,`stm`=1 where `betid` in("

func (dao *WalletDao) UpdateBetPendingGActWithStmIn(ids string, gAct mcomm.GameAction) (int64, error) {
	var sqlTmp = sqlUpdateBetPendingGActAndStm + ids + ")"
	result, err := dao.Exec(sqlTmp, gAct)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return 0, err
	}
	return result.RowsAffected()
}

const sqlQueryBetPendingStmUnsettle = "select * from wallet_bet_pending where"
const sqlQueryBetPendingStmUnsettleEx = " `betid`>? and `bettime`<? and `gact` in(3,4,6) and `stm`=0 order by `betid` asc limit ?"

func (dao *WalletDao) GetBetPendingStmUnsettle(nodeId, dateline, limit int64, betId uint64) ([]*user.WalletBetPending, error) {
	var sb strings.Builder
	var args []interface{}
	sb.WriteString(sqlQueryBetPendingStmUnsettle)
	if nodeId > 0 {
		sb.WriteString(" `nodeid`=? and ")
		args = append(args, nodeId)
	}
	sb.WriteString(sqlQueryBetPendingStmUnsettleEx)
	args = append(args, betId, dateline, limit)
	rows, err := dao.Queryx(sb.String(), args...)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return nil, err
	}
	var ret []*user.WalletBetPending
	for rows.Next() {
		rd := &user.WalletBetPending{}
		err = rows.StructScan(rd)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return nil, err
		}
		ret = append(ret, rd)
	}
	return ret, err
}
